<template>
    <div class="">
        <!-- <a-button @click="handleSave"> 保存 </a-button> -->
        <div style="border: 1px solid #ccc; margin-top: 10px">
            <Toolbar
                :editor="editorRef"
                :defaultConfig="toolbarConfig"
                :mode="mode"
                style="border-bottom: 1px solid #ccc"
            />
            <Editor
                :defaultConfig="editorConfig"
                :mode="mode"
                v-model="valueHtml"
                style="height: 400px; overflow-y: hidden"
                @onCreated="handleCreated"
                @onChange="handleChange"
            />
        </div>
        <div style="margin-top: 10px">
            <textarea v-model="valueHtml" readonly style="width: 100%; height: 200px; outline: none"></textarea>
        </div>
        <div class="prose bg-white p-4" v-html="valueHtml"></div>
    </div>
</template>

<script setup lang="ts">
import "@wangeditor-next/editor/dist/css/style.css";

import {
    type IDomEditor,
    type IEditorConfig,
    type ImageElement,
    type IToolbarConfig,
    type VideoElement
} from "@wangeditor-next/editor";
import { Editor, Toolbar } from "@wangeditor-next/editor-for-vue";
import { message } from "ant-design-vue";
import { onBeforeUnmount, onMounted, ref, shallowRef } from "vue";

import { useFileHash } from "@/hooks/useFileHash";

// 编辑器实例，必须用 shallowRef，重要！
const editorRef = shallowRef();

// 默认模式
const mode = ref<"default" | "simple">("simple");

// 内容 HTML
const valueHtml = ref("");

// 历史插入的图片列表
const historyInsertedImageList = ref<ImageElement[]>([]);
// 历史插入的视频列表
const historyInsertedVideoList = ref<VideoElement[]>([]);

// 模拟 ajax 异步获取内容
onMounted(() => {
    // setTimeout(() => {
    //     valueHtml.value = "<p>模拟 Ajax 异步设置内容</p>";
    // }, 1500);
});

const { calculateFileHash } = useFileHash();

const toolbarConfig: Partial<IToolbarConfig> = {};
const editorConfig: Partial<IEditorConfig> = {
    MENU_CONF: {
        uploadImage: {
            // 小于该值就插入 base64 格式（而不上传），默认为 0
            base64LimitSize: 5 * 1024, // 5kb
            // 自定义上传
            async customUpload(
                file: File,
                insertFn: (url: string, alt: string, href: string) => void,
                _editor: IDomEditor
            ) {
                // file 即选中的文件
                // 自己实现上传，并得到图片 url alt href

                if (file.size > 5 * 1024 * 1024) {
                    message.error("图片大小不能超过 5MB！");
                    return;
                }

                const _hash = await calculateFileHash(file);
                const res = await Apis.Storage.upload({
                    data: {
                        dirId: 1,
                        origin: "admin",
                        hash: Date.now() + "",
                        file
                    }
                });
                const info = res.data[0];
                // 最后插入图片
                // insertFn(url, alt, href);
                if (info) insertFn(info.staticServeUrl, info.fileType, info.staticServeUrl);
            }

            // 自定义文件选择器并自定义上传
            // customBrowseAndUpload(insertFn) {
            //   alert('Custom browse and upload')

            //   // Simulate async insert image
            //   setTimeout(() => {
            //     const src = 'https://www.baidu.com/img/flexible/logo/pc/result@2.png'
            //     insertFn(src, 'baidu logo', src) // insert a image
            //   }, 500)
            // },
        } as any,
        insertImage: {
            onInsertedImage(imageNode: ImageElement | null) {
                if (imageNode == null) return;
                if (imageNode.src.startsWith("data:image")) {
                    // 插入 base64 图片
                    // console.log("insert base64 image", imageNode.src);
                } else {
                    historyInsertedImageList.value.push(imageNode);
                    // 插入网络图片
                    // console.log("insert network image", imageNode.src);
                }
            }
        },
        uploadVideo: {
            // 自定义上传
            async customUpload(file: File, insertFn: (url: string, poster: string) => void) {
                // file 即选中的文件
                // 自己实现上传，并得到视频 url poster
                if (file.size > 100 * 1024 * 1024) {
                    message.error("视频大小不能超过 100MB！");
                    return;
                }

                const _hash = await calculateFileHash(file);
                const res = await Apis.Storage.upload({
                    data: {
                        dirId: 1,
                        origin: "admin",
                        hash: Date.now() + "",
                        file
                    }
                });
                const info = res.data[0];
                // 最后插入视频
                // insertFn(url, poster);
                if (info) insertFn(info.staticServeUrl, "");
            }
        } as any,
        insertVideo: {
            onInsertedVideo(videoNode: VideoElement | null) {
                if (videoNode == null) return;
                historyInsertedVideoList.value.push(videoNode);
            }
        } as any
    },
    placeholder: "请输入内容..."
};

// 组件销毁时，也及时销毁编辑器，重要！
onBeforeUnmount(() => {
    const editor = editorRef.value;
    if (editor == null) return;

    editor.destroy();
});

// 编辑器回调函数
const handleCreated = (editor: any) => {
    // console.log("created", editor);
    editorRef.value = editor; // 记录 editor 实例，重要！
};
const handleChange = (_editor: any) => {
    // console.log("change:", editor.getHtml());
};
const host = import.meta.env.VITE_API_BASE_URL;
const handleSave = async () => {
    // 获取文章中最终的图片列表
    const currentInsertedimageList = editorRef.value?.getElemsByType("image") as ImageElement[];
    const currentInsertedimageSrcList = currentInsertedimageList?.map(item => item?.src);
    // 过滤出文中曾经插入且上传了服务器的图片（不包含 base64 和外链图片）
    const toDelImageList = historyInsertedImageList.value.filter(
        item => item.src.startsWith(host) && !currentInsertedimageSrcList.includes(item.src)
    );
    // 删除服务器上无用的图片
    // if (toDelImageList.length > 0) {
    //     await Apis.FileAdmin.removeBatchByUrl({
    //         data: {
    //             urls: toDelImageList.map(item => item.src)
    //         }
    //     });
    // }

    const currentInsertedVideoList = editorRef.value?.getElemsByType("video") as VideoElement[];
    const currentInsertedVideoSrcList = currentInsertedVideoList?.map(item => item?.src);
    const toDelVideoList = historyInsertedVideoList.value.filter(
        item => item.src.startsWith(host) && !currentInsertedVideoSrcList.includes(item.src)
    );
    if (toDelVideoList.length > 0 || toDelImageList.length > 0) {
        await Apis.FileAdmin.removeBatchByUrl({
            data: {
                urls: [...toDelVideoList.map(item => item.src), ...toDelImageList.map(item => item.src)]
            }
        });
    }
};

// const handleDestroyed = editor => {
//     console.log("destroyed", editor);
// };
// const handleFocus = editor => {
//     console.log("focus", editor);
// };
// const handleBlur = editor => {
//     console.log("blur", editor);
// };
// const customAlert = (info, type) => {
//     alert(`【自定义提示】${type} - ${info}`);
// };
// const customPaste = (editor, event, callback) => {
//     console.log("ClipboardEvent 粘贴事件对象", event);

//     // 自定义插入内容
//     editor.insertText("xxx");

//     // 返回值（注意，vue 事件的返回值，不能用 return）
//     callback(false); // 返回 false ，阻止默认粘贴行为
//     // callback(true) // 返回 true ，继续默认的粘贴行为
// };

const insertText = () => {
    const editor = editorRef.value;
    if (editor == null) return;

    editor.insertText("hello world");
};

const printHtml = () => {
    const editor = editorRef.value;
    if (editor == null) return;
    console.log(editor.getHtml());
};

const disable = () => {
    const editor = editorRef.value;
    if (editor == null) return;
    editor.disable();
};

defineExpose({
    editorRef,
    valueHtml,
    toolbarConfig,
    editorConfig,
    handleCreated,
    handleChange,
    insertText,
    printHtml,
    disable
});
</script>

<style lang="scss">
.w-e-full-screen-container {
    z-index: 999;
}
.w-e-text-container [data-slate-editor] ul {
    list-style: disc;
}
.w-e-text-container [data-slate-editor] ol {
    list-style: decimal;
}

// 恢复被tailwind清除的默认样式
h1 {
    font-size: 2em;
}
h2 {
    font-size: 1.5em;
}
h3 {
    font-size: 1.17em;
}
h4 {
    font-size: 1em;
}
h5 {
    font-size: 0.83em;
}
h1,
h2,
h3,
h4,
h5 {
    font-weight: bold;
}
</style>
